/*
 * Copyright (C) 2011 asksven 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */

package cn.ieclipse.af.legcy;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;

import android.util.Log;

/**
 * A class that eases the pain of running external processes from applications.
 * Lets you run a program three ways:
 * <OL>
 * <LI><B>exec</B>: Execute the command, returning immediately even if the
 * command is still running. This would be appropriate for printing a file.
 * <LI><B>execWait</B>: Execute the command, but dont return until the command
 * finishes. This would be appropriate for sequential commands where the first
 * depends on the second having finished (e.g., <CODE>javac</CODE> followed by
 * <CODE>java</CODE>).
 * <LI><B>execPrint</B>: Execute the command and print the output. This would be
 * appropriate for the Unix command <CODE>ls</CODE>.
 * </OL>
 * Note that the PATH is not taken into account, so you must specify the
 * <B>full</B> pathname to the command, and shell built-in commands will not
 * work. For instance, on Unix the above three examples might look like:
 * <OL>
 * <LI>
 * 
 * <PRE>
 * Exec.exec(&quot;/usr/ucb/lpr Some-File&quot;);
 * </PRE>
 * 
 * <LI>
 * 
 * <PRE>
 * Exec.execWait(&quot;/usr/local/bin/javac Foo.java&quot;);
 * Exec.execWait(&quot;/usr/local/bin/java Foo&quot;);
 * </PRE>
 * 
 * <LI>
 * 
 * <PRE>
 * Exec.execPrint(&quot;/usr/bin/ls -al&quot;);
 * </PRE>
 * 
 * </OL>
 * 
 * Adapted from Core Web Programming from Prentice Hall and Sun Microsystems
 * Press, http://www.corewebprogramming.com/. © 2001 Marty Hall and Larry Brown;
 * may be freely used or adapted.
 */

public class Exec {
    
    /**
     * Starts a process to execute the command. Returns immediately, even if the
     * new process is still running.
     * 
     * @param command
     *            The <B>full</B> pathname of the command to be executed. No
     *            shell built-ins (e.g., "cd") or shell meta-chars (e.g. "&gt;")
     *            are allowed.
     * @return false if a problem is known to occur, but since this returns
     *         immediately, problems arnt usually found in time. Returns true
     *         otherwise.
     */
    
    public static ExecResult exec(String[] command) {
        return (exec(command, false, false));
    }
    
    /**
     * Starts a process to execute the command. Waits for the process to finish
     * before returning.
     * 
     * @param command
     *            The <B>full</B> pathname of the command to be executed. No
     *            shell built-ins or shell metachars are allowed.
     * @return false if a problem is known to occur, either due to an exception
     *         or from the subprocess returning a nonzero value. Returns true
     *         otherwise.
     */
    
    public static ExecResult execWait(String[] command) {
        return (exec(command, false, true));
    }
    
    /**
     * Starts a process to execute the command. Prints any output the command
     * produces.
     * 
     * @param command
     *            The <B>full</B> pathname of the command to be executed. No
     *            shell built-ins or shell meta-chars are allowed.
     * @return false if a problem is known to occur, either due to an exception
     *         or from the subprocess returning a nonzero value. Returns true
     *         otherwise.
     */
    
    public static ExecResult execPrint(String[] command) {
        return (exec(command, true, false));
    }
    
    /**
     * This creates a Process object via Runtime.getRuntime.exec() Depending on
     * the flags, it may call waitFor on the process to avoid continuing until
     * the process terminates, and open an input stream from the process to read
     * the results.
     */
    
    private static ExecResult exec(String[] command, boolean printResults,
            boolean wait) {
        ExecResult oRet = new ExecResult();
        try {
            // Start running command, returning immediately.
            Log.d("Exec.exec", "Executing command " + command);
            Process p = Runtime.getRuntime().exec(command);
            
            // Print the output. Since we read until there is no more
            // input, this causes us to wait until the process is
            // completed.
            if (printResults) {
                BufferedReader buffer = new BufferedReader(
                        new InputStreamReader(p.getInputStream()));
                String s = null;
                try {
                    while ((s = buffer.readLine()) != null) {
                        oRet.m_oResult.add(s);
                    }
                    buffer.close();
                    if (p.exitValue() != 0) {
                        oRet.m_bSuccess = false;
                        return (oRet);
                    }
                } catch (Exception e) {
                    // Ignore read errors; they mean the process is done.
                }
                
                // If not printing the results, then we should call waitFor
                // to stop until the process is completed.
            }
            else if (wait) {
                try {
                    int returnVal = p.waitFor();
                    if (returnVal != 0) {
                        oRet.m_bSuccess = false;
                        return oRet;
                    }
                } catch (Exception e) {
                    oRet.m_oError.add(e.getMessage());
                    oRet.m_bSuccess = false;
                    return oRet;
                }
            }
        } catch (Exception e) {
            oRet.m_oError.add(e.getMessage());
            oRet.m_bSuccess = false;
            return oRet;
        }
        oRet.m_bSuccess = true;
        return oRet;
    }
    
    public static void suExec(String strCommand) {
        try {
            // dirty hack:
            // http://code.google.com/p/market-enabler/wiki/ShellCommands
            Process process = Runtime.getRuntime().exec("su");
            DataOutputStream os = new DataOutputStream(
                    process.getOutputStream());
            Log.d("Exec.exec", "Executing command " + strCommand);
            
            os.writeBytes(strCommand + "\n");
            os.flush();
            os.writeBytes("exit\n");
            os.flush();
            process.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void shExec(String strCommand) {
        try {
            // dirty hack:
            // http://code.google.com/p/market-enabler/wiki/ShellCommands
            Process process = Runtime.getRuntime().exec("sh");
            DataOutputStream os = new DataOutputStream(
                    process.getOutputStream());
            Log.d("Exec.exec", "Executing command " + strCommand);
            
            os.writeBytes(strCommand + "\n");
            os.flush();
            os.writeBytes("exit\n");
            os.flush();
            process.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}